// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package websocket

import (
	"crypto/rand"
	"crypto/sha1"
	"encoding/base64"
	"io"
	"net/http"
	"strings"
)

// tokenListContainsValue returns true if the 1#token header with the given
// name contains token.
func tokenListContainsValue(header http.Header, name string, value string) bool {
	for _, v := range header[name] {
		for _, s := range strings.Split(v, ",") {
			if strings.EqualFold(value, strings.TrimSpace(s)) {
				return true
			}
		}
	}
	return false
}

var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")

func computeAcceptKey(challengeKey string) string {
	h := sha1.New()
	h.Write([]byte(challengeKey))
	h.Write(keyGUID)
	return base64.StdEncoding.EncodeToString(h.Sum(nil))
}

func generateChallengeKey() (string, error) {
	p := make([]byte, 16)
	if _, err := io.ReadFull(rand.Reader, p); err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(p), nil
}

// CopyN copies n bytes (or until an error) from src to dst.
// It returns the number of bytes copied and the earliest
// error encountered while copying.
// On return, written == n if and only if err == nil.
//
// If dst implements the ReaderFrom interface,
// the copy is implemented using it.
func CopyN(dst io.Writer, src io.Reader, n int64, buf []byte) (written int64, err error) {
	written, err = io.CopyBuffer(dst, io.LimitReader(src, n), buf)
	if written == n {
		return n, nil
	}
	if written < n && err == nil {
		// src stopped early; must have been EOF.
		err = io.EOF
	}
	return
}

// Copy copies from src to dst until either EOF is reached
// on src or an error occurs.  It returns the number of bytes
// copied and the first error encountered while copying, if any.
//
// A successful Copy returns err == nil, not err == EOF.
// Because Copy is defined to read from src until EOF, it does
// not treat an EOF from Read as an error to be reported.
//
// If src implements the WriterTo interface,
// the copy is implemented by calling src.WriteTo(dst).
// Otherwise, if dst implements the ReaderFrom interface,
// the copy is implemented by calling dst.ReadFrom(src).
// func Copy(dst io.Writer, src io.Reader) (written int64, err error) {
// 	return copyBuffer(dst, src, nil)
// }

// CopyBuffer is identical to Copy except that it stages through the
// provided buffer (if one is required) rather than allocating a
// temporary one. If buf is nil, one is allocated; otherwise if it has
// zero length, CopyBuffer panics.
// func CopyBuffer(dst io.Writer, src io.Reader, buf []byte) (written int64, err error) {
// 	if buf != nil && len(buf) == 0 {
// 		panic("empty buffer in io.CopyBuffer")
// 	}
// 	return copyBuffer(dst, src, buf)
// }

// // copyBuffer is the actual implementation of Copy and CopyBuffer.
// // if buf is nil, one is allocated.
// func copyBuffer(dst io.Writer, src io.Reader, buf []byte) (written int64, err error) {
// 	// If the reader has a WriteTo method, use it to do the copy.
// 	// Avoids an allocation and a copy.
// 	if wt, ok := src.(io.WriterTo); ok {
// 		return wt.WriteTo(dst)
// 	}
// 	// Similarly, if the writer has a ReadFrom method, use it to do the copy.
// 	if rt, ok := dst.(io.ReaderFrom); ok {
// 		return rt.ReadFrom(src)
// 	}
// 	if buf == nil {
// 		buf = make([]byte, 32*1024)
// 	}
// 	for {
// 		nr, er := src.Read(buf)
// 		if nr > 0 {
// 			nw, ew := dst.Write(buf[0:nr])
// 			if nw > 0 {
// 				written += int64(nw)
// 			}
// 			if ew != nil {
// 				err = ew
// 				break
// 			}
// 			if nr != nw {
// 				err = io.ErrShortWrite
// 				break
// 			}
// 		}
// 		if er == io.EOF {
// 			break
// 		}
// 		if er != nil {
// 			err = er
// 			break
// 		}
// 	}
// 	return written, err
// }
